package Backwards;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.*;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import Annotations.EntityNameAnnotation;
import Annotations.ValueObjectNameAnnotation;
import DomainLayer.AbstractEntity;
import DomainLayer.AbstractValueObject;
import Helpers.ApplicationConfiguration;
import Helpers.ApplicationLogger;
import Helpers.DBBackwardHelper;

import static Helpers.DBBackwardHelper.*;

public class DBBackward {

    public class TableCRUD {

        private Object currentInjection = null;
        private Map<String, String> DBConfig;

        public TableCRUD() {
            DBConfig = ApplicationConfiguration.getInstance().getDBSettings();
        }

        public TableCRUD(Object injection) {
            this();
            currentInjection = injection;
        }

        protected final String TableName() {
            String tableName = "";
            try {
                if (currentInjection instanceof AbstractEntity) {
                    tableName = currentInjection.getClass()
                            .getAnnotation(EntityNameAnnotation.class).Name();
                } else {
                    tableName = currentInjection.getClass()
                            .getAnnotation(ValueObjectNameAnnotation.class)
                            .Name();
                }
            } catch (NullPointerException e) {
                ApplicationLogger.getInstance().LOG
                        .error("Unknown object in current injection or Entity/ValueObject has not been annotated!",
                                e);
            }
            return tableName;
        }

        protected final String TableName(Object object) {
            String tableName = "";
            try {
                if (AbstractEntity.class.isAssignableFrom(object.getClass())) {
                    tableName = object.getClass()
                            .getAnnotation(EntityNameAnnotation.class).Name();
                } else {
                    tableName = object.getClass()
                            .getAnnotation(ValueObjectNameAnnotation.class)
                            .Name();
                }
            } catch (NullPointerException e) {
                ApplicationLogger.getInstance().LOG
                        .error("Unknown object in param or Entity/ValueObject has not been annotated!",
                                e);
            }
            return tableName;
        }

        public Collection<AbstractEntity> Select(String query) {
            Collection<AbstractEntity> result = new ArrayList<AbstractEntity>();

            try {
                ApplicationLogger.getInstance().LOG
                        .info("SELECT IS PROCESSING...");
                Map<String, String> DBConfig = ApplicationConfiguration
                        .getInstance().getDBSettings();
                Class.forName(DBConfig.get("DriverClass"));
                Connection connection = DriverManager.getConnection(
                        DBConfig.get("ConnectionUrl"), DBConfig.get("Login"),
                        DBConfig.get("Password"));
                connection.setAutoCommit(true);

                Statement statement = connection.createStatement(
                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_UPDATABLE);

                ResultSet resultSet = statement.executeQuery(query);
                AbstractEntity tempEntity;

                while (resultSet.next()) {
                    tempEntity = (AbstractEntity) Class.forName(
                            "DomainLayer." + TableName() + "Entity")
                            .newInstance();
                    Field[] fields = getAllFields(tempEntity.getClass());
                    Field f = null;
                    for (int k = fields.length - 1; k >= 0; --k) {
                        f = fields[k];
                        f.setAccessible(true);
                        ApplicationLogger.getInstance().LOG
                                .info(" Looking at field: " + f.getName());
                        if (isAgregator(f)) {
                            if (AbstractCollection.class.isAssignableFrom(f
                                    .getType())) {
                                ApplicationLogger.getInstance().LOG
                                        .info(" Getting a Links...");

                                Statement tempStatement = connection
                                        .createStatement(
                                                ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_UPDATABLE);
                                ApplicationLogger.getInstance().LOG
                                        .info("(trying) select "
                                                + DBBackwardHelper
                                                .getSourceTableName(f)
                                                + "_ID from "
                                                + DBBackwardHelper
                                                .getLinksTable(f)
                                                + " where "
                                                + TableName(tempEntity)
                                                + "_ID = " + tempEntity.getId());
                                ResultSet tempResultSet = tempStatement
                                        .executeQuery("select "
                                                + DBBackwardHelper
                                                .getSourceTableName(f)
                                                + "_ID from "
                                                + DBBackwardHelper
                                                .getLinksTable(f)
                                                + " where "
                                                + TableName(tempEntity)
                                                + "_ID = " + tempEntity.getId());
                                ApplicationLogger.getInstance().LOG
                                        .info("  Links getting process has been completed!");
                                ArrayList<Object> listOfVaues = new ArrayList<Object>();
                                while (tempResultSet.next()) {
                                    listOfVaues
                                            .add(Integer.parseInt((tempResultSet.getBigDecimal(DBBackwardHelper
                                                    .getSourceTableName(f)
                                                    + "_ID")).toString()));
                                }
                                ApplicationLogger.getInstance().LOG
                                        .info("  Collection values: "
                                                + listOfVaues);
                                Collection currentAgregatorCollection = (Collection) f
                                        .getType().newInstance();
                                for (Object id : listOfVaues) {
                                    ApplicationLogger.getInstance().LOG
                                            .info("  Looking at value(in collection): "
                                                    + id);
                                    Object elementOfCollection = null;
                                    try {
                                        elementOfCollection = Class
                                                .forName(
                                                        "DomainLayer."
                                                                + getAnnotatedGenericParameterType(f)
                                                                + "Entity")
                                                .newInstance();
                                    } catch (ClassNotFoundException e1) {
                                        try {
                                            elementOfCollection = Class
                                                    .forName(
                                                            "DomainLayer."
                                                                    + getAnnotatedGenericParameterType(f)
                                                                    + "ValueObject")
                                                    .newInstance();
                                        } catch (ClassNotFoundException e2) {
                                            ApplicationLogger.getInstance().LOG
                                                    .error("Unknown collection parameter!",
                                                            e2);
                                        }
                                    }
                                    Statement innerStatement = connection
                                            .createStatement(
                                                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                    ResultSet.CONCUR_UPDATABLE);
                                    ResultSet innerResultSet = innerStatement
                                            .executeQuery("select * from "
                                                    + getAnnotatedGenericParameterType(f)
                                                    + TableSuffix
                                                    + " where id = " + id);
                                    ApplicationLogger.getInstance().LOG
                                            .info("select * from "
                                                    + getAnnotatedGenericParameterType(f)
                                                    + TableSuffix
                                                    + " where id = " + id);
                                    if (elementOfCollection != null)
                                        selectEntityFiller(elementOfCollection,
                                                innerResultSet, connection);
                                    currentAgregatorCollection
                                            .add(elementOfCollection);
                                }
                                ApplicationLogger.getInstance().LOG
                                        .info("Filling collection field from: "
                                                + currentAgregatorCollection);
                                f.set(tempEntity, currentAgregatorCollection);
                            } else {
                                Statement innerStatement = connection
                                        .createStatement(
                                                ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_UPDATABLE);
                                ResultSet innerResultSet = innerStatement
                                        .executeQuery("select * from "
                                                + getAnnotatedFieldName(f)
                                                + "_table where id = "
                                                + resultSet
                                                .getObject(getAnnotatedFieldName(f)));
                                Object field = null;
                                innerResultSet.last();
                                if (innerResultSet.getRow() > 0) {
                                    innerResultSet.beforeFirst();
                                    field = f.getType().newInstance();
                                    selectEntityFiller(field, innerResultSet,
                                            connection);
                                }
                                f.set(tempEntity, field);
                            }
                        } else {
                            if (AbstractCollection.class.isAssignableFrom(f
                                    .getType())) {
                                Array tempNestedTableArray = (Array) resultSet
                                        .getObject(getAnnotatedFieldName(f));
                                Object[] arrayOfValues = (Object[]) tempNestedTableArray
                                        .getArray();
                                Collection currentSimpleCollection = (Collection) f
                                        .getType().newInstance();
                                for (int i = 0; i < arrayOfValues.length; ++i) {
                                    currentSimpleCollection
                                            .add(arrayOfValues[i]);
                                }
                                f.set(tempEntity, currentSimpleCollection);
                            } else
                                selectFieldMapper(tempEntity, f, resultSet);
                        }
                        f.setAccessible(false);
                    }
                    result.add(tempEntity);
                }
            } catch (Exception e) {
                ApplicationLogger.getInstance().LOG.error(
                        "Select method has been breaked!", e);
            } finally {
                return result;
            }
        }

        // will be replaced to DBBackwardHelper
        private void selectFieldMapper(Object object, Field f,
                                       ResultSet resultSet) {
            try {
                if (f.getType().equals(boolean.class)
                        || f.getType().equals(Boolean.class)) {
                    if (resultSet.getObject(getAnnotatedFieldName(f)).equals(
                            new BigDecimal(0)))
                        f.set(object, false);
                    else
                        f.set(object, true);
                } else if (Enum.class.isAssignableFrom(f.getType())) {
                    ApplicationLogger.getInstance().LOG.info(
                            "  Enum founded");
                    ApplicationLogger.getInstance().LOG.info(resultSet
                            .getObject(getAnnotatedFieldName(f)));
                    f.set(object, Enum.valueOf((Class) f.getType(), resultSet
                            .getObject(getAnnotatedFieldName(f)).toString()));
                } else if (f.getType().equals(Integer.class)
                        || f.getType().equals(int.class)) {
                    f.set(object,
                            Integer.parseInt(resultSet.getObject(
                                    getAnnotatedFieldName(f)).toString()));
                } else if (f.getType().equals(Double.class)
                        || f.getType().equals(double.class)) {
                    f.set(object,
                            Double.parseDouble(resultSet.getObject(
                                    getAnnotatedFieldName(f)).toString()));
                } else {
                    f.set(object, resultSet.getObject(getAnnotatedFieldName(f)));
                }
            } catch (Exception e) {
                ApplicationLogger.getInstance().LOG.info(
                        "  Exception in selectFieldMapper!", e);
            }
        }

        // will be replaced to DBBackwardHelper
        private void selectEntityFiller(Object object, ResultSet resultSet,
                                        Connection connection) {
            try {
                while (resultSet.next()) {
                    for (Field f : getAllFields(object.getClass())) {
                        f.setAccessible(true);
                        ApplicationLogger.getInstance().LOG
                                .info("   Looking at field: " + f.getName());
                        if (isAgregator(f)) {
                            if (AbstractCollection.class.isAssignableFrom(f
                                    .getType())) {
                                Object field;
                                field = Select("select * from "
                                        + getAnnotatedCollectionName(f)
                                        + " where id = "
                                        + resultSet
                                        .getObject(getAnnotatedFieldName(f)));
                                f.set(object, field);
                            } else {
                                Statement innerStatement = connection
                                        .createStatement(
                                                ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_UPDATABLE);
                                ResultSet innerResultSet = null;
                                try {
                                    innerResultSet = innerStatement
                                            .executeQuery("select * from "
                                                    + getAnnotatedFieldName(f)
                                                    + TableSuffix
                                                    + " where id = "
                                                    + resultSet
                                                    .getObject(getAnnotatedFieldName(f)));
                                } catch (SQLException e1) {
                                    try {
                                        innerResultSet = innerStatement
                                                .executeQuery("select * from "
                                                        + getSourceTableName(f)
                                                        + TableSuffix
                                                        + " where id = "
                                                        + resultSet
                                                        .getObject(getAnnotatedFieldName(f)));
                                    } catch (SQLException e2) {
                                        ApplicationLogger.getInstance().LOG
                                                .error("Wrong table name!", e2);
                                    }
                                }
                                Object field = null;
                                innerResultSet.last();
                                if (innerResultSet.getRow() > 0) {
                                    field = f.getType().newInstance();
                                    innerResultSet.beforeFirst();
                                    selectEntityFiller(field, innerResultSet,
                                            connection);
                                }
                                f.set(object, field);
                            }
                        } else {
                            selectFieldMapper(object, f, resultSet);
                        }
                        f.setAccessible(false);
                    }
                }
            } catch (Exception e) {
                ApplicationLogger.getInstance().LOG.info(
                        "  Exception when fields are under filling!", e);
            }
        }

        class Pair {
            Object first;
            Field second;

            public Pair(Object first, Field second) {
                this.first = first;
                this.second = second;
            }

            public Object getFirst() {
                return first;
            }

            public void setFirst(Object first) {
                this.first = first;
            }

            public Field getSecond() {
                return second;
            }

            public void setSecond(Field second) {
                this.second = second;
            }

        }

        public String Create() throws IllegalArgumentException, SQLException,
                ClassNotFoundException, IllegalAccessException, Exception {
            ArrayList<Pair> linkPairs = new ArrayList<Pair>();
            String id = Create(currentInjection, linkPairs);
            ApplicationLogger.getInstance().LOG
                    .info("FILLING LINK TABLES... at map " + linkPairs.size()
                            + " fiel(d/s)!");

            Map<String, String> DBConfig = ApplicationConfiguration
                    .getInstance().getDBSettings();
            Class.forName(DBConfig.get("DriverClass"));
            Connection connection = DriverManager.getConnection(
                    DBConfig.get("ConnectionUrl"), DBConfig.get("Login"),
                    DBConfig.get("Password"));

            connection.setAutoCommit(true);
            for (Pair pair : linkPairs) {
                Object object = pair.getFirst();
                Field f = pair.getSecond();
                f.setAccessible(true);
                String tempResult = "";
                Statement tempStatement = connection.createStatement(
                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_UPDATABLE);

                for (Object tempObject : (Collection) f.get(object)) {
                    tempResult = "insert into "
                            + DBBackwardHelper.getLinksTable(f) + "("
                            + TableName(object) + "_ID, "
                            + DBBackwardHelper.getSourceTableName(f)
                            + "_ID) values(" + id + ", ";
                    ApplicationLogger.getInstance().LOG
                            .info("trying to insert into: "
                                    + DBBackwardHelper.getLinksTable(f));
                    if (AbstractValueObject.class.isAssignableFrom(tempObject
                            .getClass())) {
                        try {
                            tempResult += Create(tempObject, null) + ")";
                        } catch (SQLException e) {
                            tempResult += getValueObjectID((AbstractValueObject) tempObject)
                                    + ")";
                            ApplicationLogger.getInstance().LOG.error(
                                    "That value object already exists in DB!",
                                    e);
                        }
                    } else {
                        if (AbstractCollection.class
                                .isAssignableFrom(tempObject.getClass())) {
                            DBBackward dbb = new DBBackward();
                            DBBackward.TableCRUD crud = dbb.new TableCRUD(
                                    tempObject);
                            tempResult += javaToOracleValuesConverter(crud
                                    .Create());
                        }
                        tempResult += javaToOracleValuesConverter(((AbstractEntity) tempObject)
                                .getId());
                    }
                    tempResult = tempResult.substring(0,
                            tempResult.length() - 2) + ")";
                    ApplicationLogger.getInstance().LOG.info(tempResult);
                    try {
                        tempStatement.executeUpdate(tempResult);
                    } catch (Exception e) {
                        ApplicationLogger.getInstance().LOG.info(
                                "Uncorrect insert in Link table!", e);
                    }
                }
                f.setAccessible(false);
            }
            return id;
        }

        private String Create(Object object, ArrayList<Pair> linkPairs)
                throws SQLException, ClassNotFoundException,
                IllegalArgumentException, IllegalAccessException, Exception {
            String pKValue = "unknown_value, ";

            ApplicationLogger.getInstance().LOG.info("CREATE PROCESSING...");

            Map<String, String> DBConfig = ApplicationConfiguration
                    .getInstance().getDBSettings();
            Class.forName(DBConfig.get("DriverClass"));
            Connection connection = DriverManager.getConnection(
                    DBConfig.get("ConnectionUrl"), DBConfig.get("Login"),
                    DBConfig.get("Password"));
            connection.setAutoCommit(true);

            Statement statement = connection.createStatement(
                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_UPDATABLE);

            String statementText = "begin insert into " + TableName(object)
                    + TableSuffix + "(";
            // table_name(...)
            statementText += fillSelectableRows(object);
            statementText = statementText.substring(0,
                    statementText.length() - 2) + ") values(";

            // values(...)
            statementText += fillObjectValues(object, connection, statement,
                    linkPairs);

            statementText = statementText.substring(0,
                    statementText.length() - 2)
                    + ") returning id into :id; end;";

            CallableStatement callableStatement = connection
                    .prepareCall(statementText);
            callableStatement.registerOutParameter(1, Types.NUMERIC);
            callableStatement.executeUpdate();
            pKValue = callableStatement.getBigDecimal(1).toString();

            statement.close();
            connection.close();

            return pKValue;
        }

        private String getValueObjectID(AbstractValueObject valueObject)
                throws Exception {
            String result = "";

            Map<String, String> DBConfig = ApplicationConfiguration
                    .getInstance().getDBSettings();
            Class.forName(DBConfig.get("DriverClass"));
            Connection connection = DriverManager.getConnection(
                    DBConfig.get("ConnectionUrl"), DBConfig.get("Login"),
                    DBConfig.get("Password"));
            connection.setAutoCommit(true);

            Statement statement = connection.createStatement(
                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_UPDATABLE);

            String query = "select id from " + TableName(valueObject)
                    + TableSuffix + " where ";
            String temp = "";
            for (Field f : getAllFields(valueObject.getClass())) {
                f.setAccessible(true);
                if (getAnnotatedFieldName(f).toUpperCase().equals("ID") == false) {
                    temp = getAnnotatedFieldName(f) + " = "
                            + javaToOracleValuesConverter(f.get(valueObject));
                    query += temp.substring(0, temp.length() - 2) + " and ";
                }
                f.setAccessible(false);
            }
            query = query.substring(0, query.length() - 4);

            ResultSet resultSet = statement.executeQuery(query);
            resultSet.next();
            result = resultSet.getString("id");

            return result;
        }

        private String fillSelectableRows(Object object)
                throws ClassNotFoundException {
            String result = "";
            for (Field f : getAllFields(object.getClass())) {
                if (!getAnnotatedFieldName(f).toUpperCase().equals("ID"))
                    if (((isAgregator(f) && (Collection.class
                            .isAssignableFrom(f.getType())))) == false)
                        result += getAnnotatedFieldName(f) + ", ";
            }
            return result;
        }

        private String fillObjectValues(Object object, Connection connection,
                                        Statement statement, ArrayList<Pair> linkPairs)
                throws Exception {
            String result = "";
            if (object == null)
                return "null, ";

            if (getAllFields(object.getClass()) != null) {
                for (Field f : getAllFields(object.getClass())) {
                    f.setAccessible(true);
                    ApplicationLogger.getInstance().LOG.info(" Looking at: "
                            + f.getName());
                    if (isAgregator(f)) {
                        if (Collection.class.isAssignableFrom(f.getType())) {
                            String tempResult = "";
                            if (f.get(object) != null) {
                                if (((Collection) f.get(object)).isEmpty() == false) {
                                    if (linkPairs != null) {
                                        linkPairs.add(new Pair(object, f));
                                    } else {
                                        ApplicationLogger.getInstance().LOG
                                                .info(" LinkPairs == null");
                                    }
                                }
                            } else {
                                ApplicationLogger.getInstance().LOG
                                        .info(" Empty collection of agregators!");
                            }
                        } else {
                            if (f.get(object) == null)
                                result += "null, ";
                            else if (AbstractValueObject.class
                                    .isAssignableFrom(f.getType())) {
                                try {
                                    result += Create(f.get(object), linkPairs)
                                            + ", ";
                                } catch (SQLException e) {
                                    result += getValueObjectID((AbstractValueObject) f
                                            .get(object)) + ", ";
                                    ApplicationLogger.getInstance().LOG
                                            .error("That value object already exists in DB!",
                                                    e);
                                }
                            } else {
                                result += javaToOracleValuesConverter(((AbstractEntity) f
                                        .get(object)).getId());
                            }

                        }
                    } else {
                        if (f.get(object) instanceof Collection) {
                            result += getAnnotatedCollectionName(f)
                                    + "("
                                    + getValueListFromSimpleCollection((Collection) f
                                    .get(object));
                            result = result.substring(0, result.length() - 2)
                                    + "), ";
                        } else if (!getAnnotatedFieldName(f).toUpperCase()
                                .equals("ID")) {
                            result += javaToOracleValuesConverter(f.get(object));
                        }
                    }
                    f.setAccessible(false);
                }
            }
            return result;
        }

        public void Delete(String query) {
            try {
                Map<String, String> DBConfig = ApplicationConfiguration
                        .getInstance().getDBSettings();
                Class.forName(DBConfig.get("DriverClass"));
                Connection connection = DriverManager.getConnection(
                        DBConfig.get("ConnectionUrl"), DBConfig.get("Login"),
                        DBConfig.get("Password"));
                connection.setAutoCommit(true);

                Statement statement = connection.createStatement(
                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_UPDATABLE);

                statement.executeUpdate(query);

                statement = connection.createStatement();
                statement.close();
                connection.close();
            } catch (Exception e) {
                ApplicationLogger.getInstance().LOG.error(
                        "Delete method has been breaked!", e);
            }
        }

        public void Update() {
            Update(currentInjection);
        }

        private void Update(Object object) {
            try {
                ApplicationLogger.getInstance().LOG
                        .info("UPDATE IS PROCESSING...");
                Map<String, String> DBConfig = ApplicationConfiguration
                        .getInstance().getDBSettings();
                Class.forName(DBConfig.get("DriverClass"));
                Connection connection = DriverManager.getConnection(
                        DBConfig.get("ConnectionUrl"), DBConfig.get("Login"),
                        DBConfig.get("Password"));
                connection.setAutoCommit(true);

                Statement statement = connection.createStatement(
                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                        ResultSet.CONCUR_UPDATABLE);

                String statementPrefix = "update " + TableName(object)
                        + TableSuffix + " set  ";
                String statementText = "  ";

                // filling ... set field_name = field_value, ...
                for (Field f : getAllFields(object.getClass())) {
                    f.setAccessible(true);
                    ApplicationLogger.getInstance().LOG.info(" Looking at: "
                            + f.getName());
                    if (isAgregator(f)) {
                        if (Collection.class.isAssignableFrom(f.getType())) {
                            ApplicationLogger.getInstance().LOG
                                    .info("Looking at(agregator collection):"
                                            + f.getName());
                            // Gets collection of ID for prganising foreign keys
                            // Statement innerStatement = connection
                            // .createStatement(
                            // ResultSet.TYPE_SCROLL_INSENSITIVE,
                            // ResultSet.CONCUR_READ_ONLY);
                            // ResultSet innerResultSet = null;
                            // String query = "null query";
                            // try {
                            // query = "select " + getAnnotatedFieldName(f)
                            // + " from " + TableName(object)
                            // + TableSuffix + " where id = "
                            // + ((AbstractEntity) object).getId();
                            // innerResultSet = innerStatement
                            // .executeQuery(query);
                            // } catch (Exception e1) {
                            // try {
                            // ApplicationLogger.getInstance().LOG.error(
                            // "wrong query: " + query, e1);
                            // query = "select " + getSourceTableName(f)
                            // + " from " + TableName(object)
                            // + TableSuffix + " where id = "
                            // + ((AbstractEntity) object).getId();
                            // innerResultSet = innerStatement
                            // .executeQuery(query);
                            // } catch (Exception e2) {
                            // ApplicationLogger.getInstance().LOG.error(
                            // "wrong query: " + query, e2);
                            // }
                            // }
                            // Object[] arrayOfForeignKeys = null;
                            // int arrayOfForeignKeysIndex = 0;
                            // if (innerResultSet != null) {
                            // innerResultSet.next();
                            // Array tempNestedTableArray = (Array)
                            // innerResultSet
                            // .getObject(getAnnotatedFieldName(f));
                            // arrayOfForeignKeys = (Object[])
                            // tempNestedTableArray
                            // .getArray();
                            Statement innerStatement = connection
                                    .createStatement(
                                            ResultSet.TYPE_SCROLL_INSENSITIVE,
                                            ResultSet.CONCUR_UPDATABLE);
                            ApplicationLogger.getInstance().LOG
                                    .info("trying to: "
                                            + "select "
                                            + DBBackwardHelper
                                            .getAnnotatedGenericParameterType(f)
                                            + "_ID" + " from "
                                            + DBBackwardHelper.getLinksTable(f)
                                            + " where " + TableName(object)
                                            + "_ID = "
                                            + ((AbstractEntity) object).getId());
                            ResultSet innerResultSet = null;
                            try {
                                innerResultSet = innerStatement
                                        .executeQuery("select "
                                                + DBBackwardHelper
                                                .getAnnotatedGenericParameterType(f)
                                                + "_ID"
                                                + " from "
                                                + DBBackwardHelper
                                                .getLinksTable(f)
                                                + " where "
                                                + TableName(object)
                                                + "_ID = "
                                                + ((AbstractEntity) object)
                                                .getId());
                                ApplicationLogger.getInstance().LOG
                                        .info("    ...Successful!");
                            } catch (Exception e) {
                                ApplicationLogger.getInstance().LOG.error(
                                        "Select execution failed!", e);
                            }
                            ArrayList<Object> listOfKeys = new ArrayList<Object>();
                            int arrayOfForeignKeysIndex = 0;
                            if (innerResultSet != null) {
                                while (innerResultSet.next()) {
                                    ApplicationLogger.getInstance().LOG
                                            .info("  trying to get (from result set) an "
                                                    + getSourceTableName(f)
                                                    + "_ID");
                                    listOfKeys.add(((BigDecimal) innerResultSet
                                            .getObject(getSourceTableName(f)
                                                    + "_ID")).intValue());
                                    // Array tempNestedTableArray = (Array)
                                    // innerResultSet
                                    // .getObject(getSourceTableName(f)
                                    // + "_ID");
                                    ApplicationLogger.getInstance().LOG
                                            .info("  successful!");
                                    // arrayOfForeignKeys = (Object[])
                                    // tempNestedTableArray
                                    // .getArray();
                                }
                            }

                            // statementText += getAnnotatedFieldName(f) + " = "
                            // + getAnnotatedCollectionName(f) + "(  ";
                            int key_id = 0;
                            for (Object tempObject : (Collection) f.get(object)) {
                                // if (arrayOfForeignKeys != null) {
                                for (; key_id < listOfKeys.size(); ++key_id) {
                                    ApplicationLogger.getInstance().LOG
                                            .info("      looking at tempObject: "
                                                    + tempObject);
                                    // an unicicle, sir1
                                    // String indexInArray =
                                    // (arrayOfForeignKeys[arrayOfForeignKeysIndex])
                                    // .toString();
                                    String indexInArray = (listOfKeys
                                            .get(arrayOfForeignKeysIndex))
                                            .toString();
                                    String indexInObject = (((AbstractEntity) tempObject)
                                            .getId().toString()).toString();
                                    // if ((arrayOfForeignKeysIndex <
                                    // arrayOfForeignKeys.length)
                                    // && (indexInArray
                                    // .equals(indexInObject))) {
                                    ApplicationLogger.getInstance().LOG
                                            .info("      indexInArray: "
                                                    + indexInArray);
                                    ApplicationLogger.getInstance().LOG
                                            .info("      indexInObject: "
                                                    + indexInObject);
                                    if ((key_id < listOfKeys.size())
                                            && (indexInArray
                                            .equals(indexInObject))) {
                                        // statementText +=
                                        // arrayOfForeignKeys[arrayOfForeignKeysIndex]
                                        // + ", ";
                                        // statementText += key + ", ";
                                        // ++arrayOfForeignKeysIndex;
                                        ++key_id;
                                        Update(tempObject);
                                    } else {
                                        // //////////////////////BAD
                                        // PLACE!!!/////////////////
                                        Statement tempStatement = connection
                                                .createStatement(
                                                        ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                        ResultSet.CONCUR_UPDATABLE);
                                        ApplicationLogger.getInstance().LOG
                                                .info("trying to: "
                                                        + "insert into "
                                                        + DBBackwardHelper
                                                        .getLinksTable(f)
                                                        + "("
                                                        + TableName(object)
                                                        + "_ID, "
                                                        + DBBackwardHelper
                                                        .getSourceTableName(f)
                                                        + "_ID) values("
                                                        + ((AbstractEntity) object)
                                                        .getId()
                                                        + ", "
                                                        + Create(tempObject,
                                                        null) + ")");
                                        try {
                                            tempStatement
                                                    .executeUpdate("insert into "
                                                            + DBBackwardHelper
                                                            .getLinksTable(f)
                                                            + "("
                                                            + TableName(object)
                                                            + "_ID, "
                                                            + DBBackwardHelper
                                                            .getSourceTableName(f)
                                                            + "_ID) values("
                                                            + ((AbstractEntity) object)
                                                            .getId()
                                                            + ", "
                                                            + Create(
                                                            tempObject,
                                                            null) + ")");
                                            ApplicationLogger.getInstance().LOG
                                                    .info("Successful!");
                                        } catch (Exception e) {
                                            ApplicationLogger.getInstance().LOG
                                                    .error(" Select execution has been failed...",
                                                            e);
                                        }
                                        // statementText += Create(tempObject,
                                        // null) + ", ";
                                        // //////////////////////BAD
                                        // PLACE!!!/////////////////
                                        ++key_id;
                                    }
                                }
                            }

                            // statementText = statementText.substring(0,
                            // statementText.length() - 2) + ", ";
                            // // Gets collection of ID for prganising foreign
                            // keys
                            // Statement innerStatement = connection
                            // .createStatement(
                            // ResultSet.TYPE_SCROLL_INSENSITIVE,
                            // ResultSet.CONCUR_READ_ONLY);
                            // ResultSet innerResultSet = null;
                            // String query = "null query";
                            // try {
                            // query = "select " + getAnnotatedFieldName(f)
                            // + " from " + TableName(object)
                            // + TableSuffix + " where id = "
                            // + ((AbstractEntity) object).getId();
                            // innerResultSet = innerStatement
                            // .executeQuery(query);
                            // } catch (Exception e1) {
                            // try {
                            // ApplicationLogger.getInstance().LOG.error(
                            // "wrong query: " + query, e1);
                            // query = "select " + getSourceTableName(f)
                            // + " from " + TableName(object)
                            // + TableSuffix + " where id = "
                            // + ((AbstractEntity) object).getId();
                            // innerResultSet = innerStatement
                            // .executeQuery(query);
                            // } catch (Exception e2) {
                            // ApplicationLogger.getInstance().LOG.error(
                            // "wrong query: " + query, e2);
                            // }
                            // }
                            // Object[] arrayOfForeignKeys = null;
                            // int arrayOfForeignKeysIndex = 0;
                            // if (innerResultSet != null) {
                            // innerResultSet.next();
                            // Array tempNestedTableArray = (Array)
                            // innerResultSet
                            // .getObject(getAnnotatedFieldName(f));
                            // arrayOfForeignKeys = (Object[])
                            // tempNestedTableArray
                            // .getArray();
                            // }
                            //
                            // statementText += getAnnotatedFieldName(f) + " = "
                            // + getAnnotatedCollectionName(f) + "(  ";
                            //
                            // for (Object tempObject : (Collection)
                            // f.get(object)) {
                            // if (arrayOfForeignKeys != null) {
                            // // an unicicle, sir1
                            // String indexInArray =
                            // (arrayOfForeignKeys[arrayOfForeignKeysIndex])
                            // .toString();
                            // String indexInObject = (((AbstractEntity)
                            // tempObject)
                            // .getId().toString()).toString();
                            // if ((arrayOfForeignKeysIndex <
                            // arrayOfForeignKeys.length)
                            // && (indexInArray
                            // .equals(indexInObject))) {
                            // statementText +=
                            // arrayOfForeignKeys[arrayOfForeignKeysIndex]
                            // + ", ";
                            // ++arrayOfForeignKeysIndex;
                            // Update(tempObject);
                            // } else {
                            // // //////////////////////BAD
                            // // PLACE!!!/////////////////
                            // statementText += Create(tempObject,
                            // null) + ", ";
                            // // //////////////////////BAD
                            // // PLACE!!!/////////////////
                            // ++arrayOfForeignKeysIndex;
                            // }
                            // }
                            // }
                            //
                            // statementText = statementText.substring(0,
                            // statementText.length() - 2) + "), ";
                        } else {
                            if (f.get(object) == null) {
                                statementText += getAnnotatedFieldName(f)
                                        + " = "
                                        + javaToOracleValuesConverter(f
                                        .get(object));
                            } else {
                                String keyFieldName = "";
                                Statement innerStatement = connection
                                        .createStatement(
                                                ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
                                ResultSet innerResultSet = null;
                                String query = "null query";
                                try {
                                    query = "select "
                                            + getAnnotatedFieldName(f)
                                            + " from " + TableName(object)
                                            + TableSuffix + " where id = "
                                            + ((AbstractEntity) object).getId();
                                    innerResultSet = innerStatement
                                            .executeQuery(query);
                                    keyFieldName = getAnnotatedFieldName(f);
                                } catch (Exception e1) {
                                    try {
                                        ApplicationLogger.getInstance().LOG
                                                .error("wrong query: " + query,
                                                        e1);
                                        query = "select "
                                                + getSourceTableName(f)
                                                + " from "
                                                + TableName(object)
                                                + TableSuffix
                                                + " where id = "
                                                + ((AbstractEntity) object)
                                                .getId();
                                        innerResultSet = innerStatement
                                                .executeQuery(query);
                                        keyFieldName = getSourceTableName(f);
                                    } catch (Exception e2) {
                                        ApplicationLogger.getInstance().LOG
                                                .error("wrong query: " + query,
                                                        e2);
                                    }
                                }
                                if (innerResultSet != null) {
                                    innerResultSet.next();
                                    statementText += getAnnotatedFieldName(f)
                                            + " = "
                                            + javaToOracleValuesConverter(innerResultSet
                                            .getObject(keyFieldName));
                                    Update(f.get(object));
                                } else {
                                    statementText += getAnnotatedFieldName(f)
                                            + " = null, ";
                                }
                            }
                        }
                    } else {
                        if (Collection.class.isAssignableFrom(f.getType())) {
                            statementText += getAnnotatedFieldName(f) + " = "
                                    + getAnnotatedCollectionName(f) + "(  ";
                            for (Object tempObject : (Collection) f.get(object)) {
                                if (!f.getName().toUpperCase().equals("ID"))
                                    statementText += javaToOracleValuesConverter(tempObject);
                            }
                            statementText = statementText.substring(0,
                                    statementText.length() - 2) + "), ";
                        } else if (!f.getName().toUpperCase().equals("ID"))
                            statementText += getAnnotatedFieldName(f)
                                    + " = "
                                    + javaToOracleValuesConverter(f.get(object));
                    }
                    f.setAccessible(false);
                }
                statementText = statementText.substring(0,
                        statementText.length() - 2);
                if (AbstractEntity.class.isAssignableFrom(object.getClass()))
                    statementText += " where id = "
                            + ((AbstractEntity) object).getId();
                if (AbstractValueObject.class.isAssignableFrom(object
                        .getClass()))
                    statementText += " where id = "
                            + ((AbstractValueObject) object).getId();
                ApplicationLogger.getInstance().LOG.info("statement text: "
                        + statementPrefix + statementText);
                statement.executeUpdate(statementPrefix + statementText);
                statement.close();
                connection.close();
            } catch (Exception e) {
                ApplicationLogger.getInstance().LOG.error(
                        "unexpected ecxeption of update method!", e);
            }
        }
    }
}
